#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include <math.h>
//#include "vector"
#include "rngs.h"

#define DEBUG 0
#define NUM_TESTS 1000
#define NOISY_TEST 0

float rndm() {
	struct timeval tv;
	float retVal;
	
	gettimeofday(&tv, NULL);  //the only way this 
	retVal = tv.tv_usec * tv.tv_sec;
	while (retVal > 1.0) {
		retVal = retVal / 10;
	}
	retVal = retVal * (float)rand()/RAND_MAX;
	if(retVal < 0) {retVal = retVal * (-1);}
	return retVal;
}

int adventureTest(int testIteration, struct gameState *state) {
	int i;
	int currentTurn, firstTreas = -1, secTreas = -1, firstTreasPos = -1, secTreasPos = -1, deckHasTwoTreas = 0;
	int numDeckPre = 0;
	int preDeckCopy[MAX_DECK];
	int preDiscardCopy[MAX_DECK];
	int preHandCopy[MAX_HAND];
	int success = 1;
	//set all the card id's to -1
	/* std::fill_n(preDeckCopy, 100, -1); //syntax from http://stackoverflow.com/questions/1065774/c-c-initialization-of-a-normal-array-with-one-default-value
	std::fill_n(preDiscardCopy, 100, -1);
	std::fill_n(preHandCopy, 100, -1); */
	int adventurerPresent = -1; //to ensure that adventurer is in the hand
	int preHandTreasCount = 0, postHandTreasCount = 0;
	//int deckCorrect = 1;
	currentTurn = 0;
	if (state->handCount[currentTurn] > 0) { //check if hand is empty
		for (i=0;i<state->handCount[currentTurn];i++) {	//check if adventurer is present
			if (state->hand[currentTurn][i] == adventurer) {adventurerPresent = i;}
		}
	} else {
		for (i=0;i<5;i++) { //fill hand if empty
			state->hand[currentTurn][i] = (int) roundf( treasure_map * rndm() );
			state->handCount[currentTurn] = i + 1;
		}
	}
	//assign adventurer to a random spot in the hand if it's not already present
	if (adventurerPresent == -1){
		adventurerPresent = (int) roundf( (state->handCount[currentTurn]-1)		* rndm() );
		state->hand[currentTurn][adventurerPresent] = adventurer;
	}
	if (NOISY_TEST == 1)
		printf("\tPre-play hand: ");
	for(i=0;i<state->handCount[currentTurn];i++) { //print hand
		if (NOISY_TEST == 1)
			printf("%d, ",state->hand[currentTurn][i]);
	}
	if (NOISY_TEST == 1)
		printf("\n");
	//make copy of the current hand to check that adventurer worked
	for (i=0;i<state->handCount[currentTurn];i++) {
		preHandCopy[i] = state->hand[currentTurn][i];
		if (state->hand[currentTurn][i] > 3 && state->hand[currentTurn][i] < 7) {
			preHandTreasCount += 1; // count current number of treasures
		}
	}	
	//track cards in deck until second treasure card
	for (numDeckPre=0;numDeckPre<state->deckCount[currentTurn];numDeckPre++) {
		preDeckCopy[numDeckPre] = state->deck[currentTurn][numDeckPre];
		if (state->deck[currentTurn][numDeckPre] > 3 && state->deck[currentTurn][numDeckPre] < 7) {
			if (firstTreas == -1) {
				firstTreas = state->deck[currentTurn][numDeckPre];
				firstTreasPos = numDeckPre;
			} else {
				secTreas = state->deck[currentTurn][numDeckPre];
				secTreasPos = numDeckPre;
			}
		}
	}
	if (secTreasPos > 0) {
		deckHasTwoTreas = 1;	
	} else {	//if less than two treasure cards found in deck, see if there are more in the discard pile
		for (i=0;i<state->discardCount[currentTurn];i++) {
			preDiscardCopy[i] = state->discard[currentTurn][i];
			if (state->discard[currentTurn][i] > 3 && state->discard[currentTurn][i] < 7) {
				if (firstTreas == -1) {
					firstTreas = state->hand[currentTurn][i];
					firstTreasPos = i + numDeckPre;
				}
				else {
					secTreas = state->hand[currentTurn][i];
					secTreasPos = i + numDeckPre;
					break;
				}
			}
		}
	}
	assert (0 == cardEffect(adventurer, 0,0,0,state,adventurerPresent,0));
	if (state->hand[currentTurn][adventurerPresent] == adventurer) {
		//if there are other adventurers in the hand, it will be at a lower index (var is set as last instance)
		printf("\tTEST %d FAILED:  Adventurer still present in hand after being played\n", testIteration);
		success = 0;
		printf("\tPost-play hand: ");
		for(i=0;i<state->handCount[currentTurn];i++) { //print hand
			printf("%d, ",state->hand[currentTurn][i]);
		}
		printf("\n");
	}
	//establish how many treasures are currently in the hand
	for (i=0;i<state->handCount[currentTurn];i++) {
		if(state->hand[currentTurn][i] > 3 && state->hand[currentTurn][i] < 7) {
			postHandTreasCount += 1;
		}
	}
	if (secTreasPos != -1) {
		//at least two treasures are in the deck/discard stacks
		if (postHandTreasCount != 2 + preHandTreasCount) {
			printf("\tTEST %d FAILED:  number of treasures in hand should be %d, but is %d\n", testIteration, preHandTreasCount + 2, postHandTreasCount);
			success = 0;
		} 
		/* if (secTreasPos <= numDeckPre) {
			for(i=0;i<state->deckCount[currentTurn];i++) { 
				if ( ( i > state->deckCount[currentTurn]) || (preDeckCopy[i+secTreasPos] == -1) ) {
					//either all the current deck cards have been looked at or all the previous deck cards
					break;
				} else if (state->deck[currentTurn][i] != preDeckCopy[i+secTreasPos]) {
					deckCorrect = 0;
				}
			}
			if (deckCorrect == 0) 
				printf("   TEST %d FAILED:  Deck did not shift correctly\n", testIteration);
				printf("\tThe %dth card in the deck was the second treasure,\n",secTreasPos);
				printf("\tso the next card should now be the first, but it was %d and the first is now: %d\n", 
							preDeckCopy[secTreasPos+1], state->deck[currentTurn][0]);
		} */
	} else if(firstTreasPos != -1) {
		//only one treasure found in deck/discard
		if (postHandTreasCount != 1 + preHandTreasCount) {
			printf("\tTEST %d FAILED:  number of treasures in hand should be %d, but is %d\n", testIteration, preHandTreasCount + 2, postHandTreasCount);
			success = 0;
		}
	} else {
		//no treasures found in deck/discard
		if (postHandTreasCount != preHandTreasCount) {
			printf("\tTEST %d FAILED:  number of treasures in hand should be %d, but is %d\n", testIteration, preHandTreasCount + 2, postHandTreasCount);
			success = 0;
		}
		
	}
	if (success == 1 && NOISY_TEST == 1) {
		printf ("   TEST %d SUCCEEDED\n", testIteration);
	}
	return 0;
}

int main(int argc, char **argv) {
	int i, j, k;
	int adventurerPresent = 0; //used to ensure that adventurer gets in the game
	int numPlayers, seed, card[10];
	struct gameState G;
	int numPassed = 0, numFailed = 0;
	printf("Starting random test for adventurer:\n");
	for (i=0;i<NUM_TESTS;i++) {
		if (NOISY_TEST == 1)
			printf("Starting test %d:\n", i);
		numPlayers = (int) roundf( (MAX_PLAYERS-2) * rndm() ) + 2;
		if (NOISY_TEST == 1)
			printf("\t%d players", numPlayers);
		seed = (int) roundf( 32767 * rndm() );  //generate a random seed
		if (NOISY_TEST == 1)
			printf("\t%d seed\n", seed);
		for (j=0;j<10;j++) { // assign the ten cards for the game
			card[j] = (int) roundf( treasure_map * rndm() ); //use highest-numbered card as max of rndm()
			for (k=0;k<j;k++) { 
				if (card[k] == card[j]) { 
					j = j - 1;
				} 
			} // ensure no cards are assigned in duplicate
			if (card[j] == adventurer) {adventurerPresent = 1;} //verify if this is adventurer
		}
		//put adventurer in a random  position, only if it's not already in the game
		if (adventurerPresent == 0) { card[ (int) roundf( 10*rndm() ) ] = adventurer;}
		
		initializeGame(numPlayers, card, seed, &G);
		if (adventureTest(i, &G) == 0)
			numPassed += 1;
		else
			numFailed += 1;
	}
	printf("%d%% success, %d tests passed and %d failed\n", 100*numPassed/NUM_TESTS, numPassed, numFailed);
	return 0;
}



